#ifndef MONITOR_H_
#define MONITOR_H_
#include <iostream>
#include <string>
#include <cstdlib>
#include <fstream>
#include "../Utils/directoryHandler.h"
#include "../Utils/index.h"
#include <log4cpp/Category.hh>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/SimpleLayout.hh>
#include <log4cpp/TimeStamp.hh>
extern log4cpp::Category& category;
class Monitor {
private:
	string properties_directory;
	string properties_file_path;
	string properties_file_name;
	string accounts_file_path;
	string storage_path;
	Index* accounts_index;
	Index* cfg_index;
public:
	Monitor(string& a, string& b) {
		accounts_index = 0;
		cfg_index = 0;
		this->properties_directory = a;
		this->properties_file_name = b;
		this->properties_file_path = properties_directory + "/"
				+ properties_file_name;
	}

	~Monitor() {
		if (accounts_index!=0) {
			delete accounts_index;
		}
		if(cfg_index!=0) {
			delete cfg_index;
		}
	}

	void CreatePropertiesFile() {
		ofstream ofs;
		ofs.open(properties_file_path.c_str(), ios::out);
		//Valores por defecto
		ofs.close();
		cfg_index->LoadFromDisk();
		string p("PORT");
		string port("33333");
		string s("STORAGE_FOLDER");
		string storage(".");
		cfg_index->AddKey(&p,&port);
		cfg_index->AddKey(&s,&storage);
		cfg_index->SaveToDisk();
		category.notice("Creating default properties file");
	}

	void CreateAccountsFile(string* s) {
		ofstream ofs;
		ofs.open(s->c_str(), ios::out);
		ofs.close();
		category.notice("Creating empty accounts file");
	}

	void CreateAccountFolders(string* user_name) {
		string users_folder = this->storage_path + "/" + "users_files";
		directoryHandler dir(&users_folder);
		//Creo carpeta con el nombre del usuario
		dir.createFolder(user_name);
		string user_folder = users_folder + "/" + *user_name;
		directoryHandler dir2(&user_folder);
		string f("files");
		//Creo carpeta files dentro de la carpeta del usuario
		dir2.createFolder(&f);
		category.notice("Creating folder "+users_folder);
		//Creo archivos de indices, dentro de la carpeta del usuario
		string files_dat_path = user_folder + "/" + "files.dat";
		ofstream ofs;
		ofs.open(files_dat_path.c_str(), ios::out);
		ofs.close();
		category.notice("Creating file "+files_dat_path);
	}

	void DeleteAccountFolders(string* user_name) {
		string users_folder = this->storage_path + "/" + "users_files";
		directoryHandler dir(&users_folder);
		if (dir.folderExists(user_name)) {
			dir.deleteFolder(user_name);
			category.notice("Deleting folder "+users_folder);

		}
	}

	string CreateAccount(string* user, string* pass) {
	string result("Account created.");
		if (!accounts_index->KeyExists(user)) {
		accounts_index->AddKey(user, pass);
			category.notice(
					"Creating new account: user:" + *user + " pass:" + *pass);
			CreateAccountFolders(user);
			category.notice("Creating needed folders for account:" + *user);
		} else {
			category.error("Account " + *user + " already exists");
			result="Error: account already exists";
		}
		return result;
	}

	string EditAccount(string* user,string* pass) {
		string result("Account edited");
		if (accounts_index->KeyExists(user)) {
			accounts_index->EditKey(user, pass);
			category.notice(
					"Account: " + *user + " changed password to: " + *pass);
		} else {
			category.error(
					"Error: Account " + *user + " doesn't exist"
							+ " can't edit");
			result="Account doesn't existe, can't edit";
		}
		return result;

	}

	string DeleteAccount(string* user) {
		string result="Account deleted";
		if (accounts_index->KeyExists(user)) {
			accounts_index->DeleteKey(user);
			DeleteAccountFolders(user);
			category.notice(
					"Deleting account information and folders for account:"
							+ *user);
		} else {
			category.error(
					"Error: Account " + *user + " doesn't exist"
							+ " can't be deleted");
			result="Account doesn't exist, can't be deleted";
		}
		return result;
	}

	void SaveNewAccountsFile() {
		accounts_index->SaveToDisk();
		category.notice("Saving accounts file to disk");
	}

	void InitializeAccounts() {
		string users_file_name = "users.dat";
		string st("STORAGE_FOLDER");
		category.notice("Initializing accounts from file");
		storage_path=cfg_index->GetSecond(&st);
		string accounts_file_path = this->storage_path + "/" + "users_files/"
				+ users_file_name;
		directoryHandler dirh(&storage_path);
		string uf("users_files");
		if(!dirh.folderExists(&uf)) {
			dirh.createFolder(&uf);
		}
		string g = storage_path + "/users_files";
		category.info("Users accounts file path is " + accounts_file_path);
		directoryHandler dir(&g);
		if (!dir.fileExists(&users_file_name)) {
			category.info("Users accounts file doesn't exist");
			CreateAccountsFile(&accounts_file_path);
		}
		accounts_index = new Index(&accounts_file_path);
		accounts_index->LoadFromDisk();
		category.notice("Accounts file loaded from disk");


	}

	int ChangePort(string* new_port) {
		string p("PORT");
		cfg_index->EditKey(&p, new_port);
		category.notice("Connection port was changed to "+*new_port);
		return 1;
	}

	int ChangeStoragePath(string* new_storage) {
		string s("STORAGE_FOLDER");
		cfg_index->EditKey(&s, new_storage);
		category.notice("Storage path was changed to "+*new_storage);
		return 1;
	}

	void SaveNewConfiguration() {
		string sf("STORAGE_FOLDER");
		this->storage_path = cfg_index->GetSecond(&sf);
		directoryHandler dirh(&storage_path);
			string uf("users_files");
			if(!dirh.folderExists(&uf)) {
				dirh.createFolder(&uf);
			}
		directoryHandler h(&this->storage_path);
		//Verifico que exista la carpeta users_files en el storage path
		string users_data_folder("users_files");
		if (!h.folderExists(&users_data_folder)) {
			//Si no existe la creo
			category.warn(
					"users_files folder doesn't exist in "
							+ this->storage_path);
			h.createFolder(&users_data_folder);
			category.notice("users_files created in " + this->storage_path);
		}
		category.notice("New cfg properties fie saved to disk");
		cfg_index->SaveToDisk();
	}

	void InitializeCfg() {
		category.notice("Initializing configuration from file");
		category.info("Properties cfg file path is " + properties_file_path);
		directoryHandler dir(&properties_directory);
		//Si no existe el archivo, lo creo con parametros por default
		cfg_index = new Index(&properties_file_path);
		if (!dir.fileExists(&properties_file_name)) {
			category.warn("Properties file doesn't exist");
			CreatePropertiesFile();
		}
		else {
			cfg_index->LoadFromDisk();
		}

		category.notice("Properties file loaded from disk");
	}

	map<string,string> GetAllAccounts(){
		return accounts_index->GetMappedIndex();
	}

	string GetStorage() {
		string key("STORAGE_FOLDER");
		return this->cfg_index->GetSecond(&key);
	}

	string GetPort() {
			string key("PORT");
			return this->cfg_index->GetSecond(&key);
		}

};
#endif
